package top.zlcode.friend.service.exam.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.zlcode.common.core.context.UserContextHelper;
import top.zlcode.common.core.domain.TableDataInfo;
import top.zlcode.common.core.enums.ResultCode;
import top.zlcode.common.security.exception.ServiceException;
import top.zlcode.friend.domain.exam.Exam;
import top.zlcode.friend.domain.exam.ExamQuestion;
import top.zlcode.friend.domain.exam.dto.ExamQueryDTO;
import top.zlcode.friend.domain.exam.dto.ExamRankDTO;
import top.zlcode.friend.domain.exam.vo.ExamDetailVO;
import top.zlcode.friend.domain.exam.vo.ExamRankVO;
import top.zlcode.friend.domain.exam.vo.ExamVO;
import top.zlcode.friend.domain.question.Question;
import top.zlcode.friend.domain.question.vo.QuestionVO;
import top.zlcode.friend.domain.user.vo.UserVO;
import top.zlcode.friend.manager.ExamCacheManager;
import top.zlcode.friend.manager.UserCacheManager;
import top.zlcode.friend.mapper.exam.ExamMapper;
import top.zlcode.friend.mapper.exam.ExamQuestionMapper;
import top.zlcode.friend.mapper.question.QuestionMapper;
import top.zlcode.friend.mapper.user.UserExamMapper;
import top.zlcode.friend.service.exam.IExamService;

import java.util.List;

@Service
public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements IExamService {

    @Autowired
    private ExamCacheManager examCacheManager;

    @Autowired
    private UserExamMapper userExamMapper;

    @Autowired
    private UserCacheManager userCacheManager;

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private ExamQuestionMapper examQuestionMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public TableDataInfo queryPage(ExamQueryDTO examQueryDTO) {
        Long total = examCacheManager.getListSize(examQueryDTO.getType(), null);
        List<ExamVO> examVoList;
        // 条件查询不走 redis, 并且不缓存数据
        if (examQueryDTO.getStartTime() != null && examQueryDTO.getEndTime() != null) {
            PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());
            examVoList = baseMapper.queryPage(examQueryDTO);
            total = new PageInfo<>(examVoList).getTotal();
        } else if (total == null || total == 0) {
            PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());
            examVoList = baseMapper.queryPage(examQueryDTO);
            examCacheManager.refreshCache(examQueryDTO.getType(), null);
            total = new PageInfo<>(examVoList).getTotal();
        } else {
            examVoList = examCacheManager.getExamVOList(examQueryDTO, null);
            total = examCacheManager.getListSize(examQueryDTO.getType(), null);
        }
        if (CollUtil.isEmpty(examVoList)) {
            return TableDataInfo.empty();
        }

        assembleExamVOList(examVoList);
        return TableDataInfo.success(examVoList, total);
    }

    private void assembleExamVOList(List<ExamVO> examVoList) {
        Long userId = UserContextHelper.getUserId();
        List<Long> userExamIdList = examCacheManager.getAllUserExamList(userId);
        if (CollUtil.isEmpty(userExamIdList)) {
            return;
        }
        for (ExamVO examVO : examVoList) {
            if (userExamIdList.contains(examVO.getExamId())) {
                examVO.setEnter(true);
            }
        }
    }

    @Override
    public String getFirstQuestion(Long examId) {
        checkAndRefresh(examId);
        return examCacheManager.getFirstQuestion(examId).toString();
    }

    @Override
    public String preQuestion(Long examId, Long questionId) {
        checkAndRefresh(examId);
        return examCacheManager.preQuestion(examId, questionId).toString();
    }

    @Override
    public String nextQuestion(Long examId, Long questionId) {
        checkAndRefresh(examId);
        return examCacheManager.nextQuestion(examId, questionId).toString();
    }

    @Override
    public ExamDetailVO detail(Long examId) {
        ExamDetailVO examDetailVO = new ExamDetailVO();
        Exam exam = getExam(examId);
        BeanUtil.copyProperties(exam, examDetailVO);
        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(new LambdaQueryWrapper<ExamQuestion>()
                .select(ExamQuestion::getQuestionId)
                .eq(ExamQuestion::getExamId, exam.getExamId())
                .orderByAsc(ExamQuestion::getQuestionOrder));

        if (CollectionUtil.isEmpty(examQuestionList)) {
            return examDetailVO;
        }

        List<Long> questionIdList = examQuestionList.stream().map(ExamQuestion::getQuestionId).toList();
        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>()
                .select(Question::getQuestionId, Question::getTitle, Question::getDifficulty)
                .in(Question::getQuestionId, questionIdList));

        List<QuestionVO> questionVOList = BeanUtil.copyToList(questionList, QuestionVO.class);
        examDetailVO.setExamQuestionList(questionVOList);
        return examDetailVO;
    }

    @Override
    public TableDataInfo rankList(ExamRankDTO examRankDTO) {
        Long total = examCacheManager.getRankListSize(examRankDTO.getExamId());
        List<ExamRankVO> examRankVOList;
        if (total == null || total <= 0) {
            PageHelper.startPage(examRankDTO.getPageNum(), examRankDTO.getPageSize());
            examRankVOList = userExamMapper.selectExamRankList(examRankDTO.getExamId());
            examCacheManager.refreshExamRankCache(examRankDTO.getExamId());
            total = new PageInfo<>(examRankVOList).getTotal();
        } else {
            examRankVOList = examCacheManager.getExamRankList(examRankDTO);
        }
        if (CollectionUtil.isEmpty(examRankVOList)) {
            return TableDataInfo.empty();
        }
        assembleExamRankVOList(examRankVOList);
        return TableDataInfo.success(examRankVOList, total);
    }

    private void assembleExamRankVOList(List<ExamRankVO> examRankVOList) {
        if (CollectionUtil.isEmpty(examRankVOList)) {
            return;
        }
        for (ExamRankVO examRankVO : examRankVOList) {
            Long userId = examRankVO.getUserId();
            UserVO user = userCacheManager.getUserById(userId);
            examRankVO.setNickName(user.getNickName());
        }
    }

    private void checkAndRefresh(Long examId) {
        Long listSize = examCacheManager.getExamQuestionListSize(examId);
        if (listSize == null || listSize <= 0) {
            examCacheManager.refreshExamQuestionCache(examId);
        }
    }

    private Exam getExam(Long examId) {
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.EXAM_NOT_EXISTS);
        }
        return exam;
    }
}
